//
// Created by Tony on 2024/6/11.
//

#ifndef COMPILER_CODE_GENERATOR_H
#define COMPILER_CODE_GENERATOR_H

#include "../tvm/rt_code/ClassTable.h"
#include "../tvm/rt_code/Code.h"
#include "Visitor.h"
#include <cstdint>

namespace Compiler {

class CodeGenerator final : public Visitor {
    // params
    shared_ptr<RtCode::ClassTable> mClassTable;
    shared_ptr<RtCode::Class> mClass;
    shared_ptr<RtCode::Method> mMethod;

    // inner
    shared_ptr<RtCode::Code> code() { return mMethod->getCode(); }
    RtCode::ConstantPool& constantPool() { return mClass->getConstantPool(); }
    int16_t forwardOffset(int32_t dest) { return static_cast<int16_t>(code()->size() - dest); }
    int16_t backwardOffset(int32_t dest) { return static_cast<int16_t>(dest - code()->size()); }

public:
    explicit CodeGenerator(const shared_ptr<RtCode::ClassTable>& classTable)
        : mClassTable(classTable) {}
    CodeGenerator(const shared_ptr<RtCode::Class>& clazz,
                  const shared_ptr<RtCode::ClassTable>& classTable,
                  const shared_ptr<RtCode::Method>& method)
        : mClassTable(classTable), mClass(clazz), mMethod(method) {}

    shared_ptr<RtCode::Class> getClass() { return mClass; }

    shared_ptr<RtCode::Method> getMethod() { return mMethod; }

    // abstract ast
    int32_t visit(Parser::Ast* ast) override;

    // Literal
    int32_t visit(Parser::BooleanLiteral* ast) override;
    int32_t visit(Parser::CharLiteral* ast) override;
    int32_t visit(Parser::Flt64Literal* ast) override;
    int32_t visit(Parser::Int64Literal* ast) override;
    int32_t visit(Parser::NullLiteral* ast) override;
    int32_t visit(Parser::StringLiteral* ast) override;

    // Name
    int32_t visit(Parser::Name* ast) override;

    // Op
    int32_t visit(Parser::Operator* ast) override;

    // Expr
    int32_t visit(Parser::BinaryExpr* ast) override;
    int32_t visit(Parser::TernaryExpr* ast) override;
    int32_t visit(Parser::UnaryExpr* ast) override;

    // Type Tag
    int32_t visit(Parser::TypeTag* ast) override;
    int32_t visit(Parser::AccessFlags* ast) override;

    // Statement
    int32_t visit(Parser::SimpleStmt* ast) override;
    int32_t visit(Parser::AssertStmt* ast) override;
    int32_t visit(Parser::BlockStmt* ast) override;
    int32_t visit(Parser::ForStmt* ast) override;
    int32_t visit(Parser::IfStmt* ast) override;
    int32_t visit(Parser::NullStmt* ast) override;
    int32_t visit(Parser::VarDefStmt* ast) override;
    int32_t visit(Parser::ReturnStmt* ast) override;

    // array
    int32_t visit(Parser::ArrayIndex* ast) override;

    // function
    int32_t visit(Parser::ParameterList* ast) override;
    int32_t visit(Parser::FunctionDefine* ast) override;
    int32_t visit(Parser::ArgumentList* ast) override;

    // module
    int32_t visit(Parser::Module* ast) override;

    // class
    int32_t visit(Parser::FieldDefine* ast) override;
    int32_t visit(Parser::MethodDefine* ast) override;
    int32_t visit(Parser::NativeMethodDecl* ast) override;
    int32_t visit(Parser::ClassBody* ast) override;
    int32_t visit(Parser::ClassDefine* ast) override;
    int32_t visit(Parser::ClassModule* ast) override;

    // view
    int32_t visit(Parser::ViewBuilder* ast) override;
    int32_t visit(Parser::ViewBuilderList* ast) override;
    int32_t visit(Parser::ViewBuilderBlock* ast) override;
    int32_t visit(Parser::AttributeSetter* ast) override;
    int32_t visit(Parser::AttributeSetterList* ast) override;
};

} // namespace Compiler

#endif // COMPILER_CODE_GENERATOR_H
